const { generateKeyPairSync, createSign, createVerify, createHash, } = require('crypto');
const base64Url = require('base64-url');

// 生成密钥对的加密类型
const KEY_PAIR_TYPE = 'rsa';
// 密钥长度
const kEY_LENGTH = 1024;
// 签名的摘要算法类型
const SIGN_TEPE = 'sha256';
// token 类型
const TOKEN_TYPE = 'jwt';
// 签名格式
const SIAN_FORMAT = 'hex';
// jwt 标识
const tag = '.';
const ERROR_TAGS = ['undefined', 'null', '0', 'false', 'true', 'NaN'];

/**
 * @description 生成 rsa 加密算法的公钥和私钥的密钥对
 */
const { publicKey, privateKey } = generateKeyPairSync(KEY_PAIR_TYPE, {
    modulusLength: kEY_LENGTH,
});

/**
 * @description 使用 base64URL 对目标对象进行编码
 * @param {*} object - base64URL 编码的目标对象
 * @returns - 返回 base64URL 编码后的结果
 */
const base64Encode = (object) => base64Url.encode(JSON.stringify(object));
/**
 * @description 使用 base64URL 对目标编码字符串进行解码
 * @param {*} base64Str - base64URL 编码后的字符串 
 * @returns - 返回结果对象
 */
const base64Decode = (base64Str) => base64Url.decode(base64Str);

/**
 * @description 生成 token
 * @param {*} options - 生成 token 的参数【用户唯一标识 key、token 过期时间】
 * @returns 返回生成的 token
 */
exports.generateToken = (options) => {
    const { userKey, expires, } = options;
    // 创建 jwt header
    const header = base64Encode({
        alg: SIGN_TEPE,
        typ: TOKEN_TYPE,
    });
    // 创建 jwt payload
    const payload = base64Encode({
        iss: 'jy',
        exp: +new Date() + expires,
        key: userKey,
    });
    // 创建 jwt 的 rsa 非对称加密算法签名
    const sign = createSign(SIGN_TEPE);
    // 对 jwt 的 header 和 payload 进行签名
    sign.update(`${header}${tag}${payload}`);
    sign.end();
    // 通过 rsa 私钥进行签名
    const signature = sign.sign(privateKey, SIAN_FORMAT);
    // 创建 jwt
    const jwt = `${header}${tag}${payload}${tag}${signature}`;
    return jwt;
};

/**
 * @description 校验 token
 * @param {*} jwt - jwt
 * @returns - 返回 token 校验结果
 */
exports.verifyToken = (jwt) => {
    const verify = createVerify(SIGN_TEPE);
    const splits = jwt.split(tag);
    if( splits?.length < 3 || splits.some(item => ERROR_TAGS.includes(item) || !item)) return { usable: false };
    const [header, payload, signature] = splits;
    verify.update(`${header}${tag}${payload}`);
    verify.end();
    let result = verify.verify(publicKey, signature, SIAN_FORMAT);
    const data = {};
    if(result) {
        const object = base64Decode(payload);
        data.userKey = object?.key;
        result = object?.exp > +new Date();
    }
    return {
        usable: result,
        data,
    };
};
/**
 * @description 生成 md5 唯一 key
 * @param {*} options - 传入的生成 key 值的参数对象
 * @returns - 返回一个根据用户参数对象生成的 md5 格式的唯一摘要
 */
exports.generateUniqueKey = (options = {}) => {
    let uniKey = '';
    for (const key in options) {
        if (Object.hasOwnProperty.call(options, key)) {
            const value = options[key];
            uniKey += value;
        }
    }
    const hash = createHash('md5');
    return hash.update(uniKey).digest('hex');
};